package ar.edu.sccs.model.wordnet;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.didion.jwnl.data.POS;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import ar.edu.sccs.entities.Case;
import ar.edu.sccs.entities.Dimension;
import ar.edu.sccs.monitoring.logging.SCCSLogger;
import ar.edu.sccs.util.Constants;

public class SemanticModule {

	static Logger logger = SCCSLogger.getLogger(SemanticModule.class);

	private Case targetCase;

	public SemanticModule() {
		try {
			WordNetHelper.initialize(new URL("file:" + System.getProperty("jboss.server.home.dir") + Constants.Resources.WORDNET_CONFIG));
		} catch (Exception e) {
			logger.fatal("WordNetSimilarity.newInstance: NULL RETURN", e);
		}
	}

	public List<Case> getSemantic(Case targetCase) {
		this.targetCase = targetCase;

		List<String> listClassName = getDimensionSemantic(targetCase, Constants.Dimension.Class.NAME, POS.NOUN, Constants.Semantic.LIMIT_CLASS);
		List<String> listMethodObject = getDimensionSemantic(targetCase, Constants.Dimension.Method.OBJECT, POS.NOUN, Constants.Semantic.LIMIT_OBJECT);
		List<String> listMethodAction = getDimensionSemantic(targetCase, Constants.Dimension.Method.ACTION, POS.VERB, Constants.Semantic.LIMIT_ACTION);

		return getCombination(listClassName, listMethodObject, listMethodAction);
	}

	private List<String> getDimensionSemantic(Case targetCase, String dimensionName, POS wordType, int dimensionLimit) {
		List<String> listSemantic = new ArrayList<String>();

		Dimension dimension = targetCase.getDimensions().get(dimensionName);
		if (dimension != null) {
			if (dimension.getSemantic()) {
				logger.debug("SemanticModule.getDimensionSemantic '" + dimensionName + "' for: " + (String) dimension.getValue());
				listSemantic = WordNetHelper.getSynonymy((String) dimension.getValue(), wordType, dimensionLimit);
			} else {
				listSemantic.add((String) dimension.getValue());
			}
		}

		return listSemantic;
	}

	private List<Case> getCombination(List<String> listClassName, List<String> listMethodObject, List<String> listMethodAction) {
		List<Case> listCase = new ArrayList<Case>();
		
		if (listClassName == null || listMethodObject == null || listMethodAction == null) {
			logger.fatal("SemanticModule.getCombination FATAL");
			return null;
		}

		for (int i = 0; i < listClassName.size(); i++)
			StringUtils.capitalize(listClassName.get(i));
		for (int i = 0; i < listMethodObject.size(); i++)
			StringUtils.capitalize(listMethodObject.get(i));

		if (listClassName.size() > 0 && listMethodObject.size() > 0 && listMethodAction.size() > 0) {
			listCase = getCombination(listClassName, Constants.Dimension.Class.NAME, listMethodObject, Constants.Dimension.Method.OBJECT,
					listMethodAction, Constants.Dimension.Method.ACTION);
			logger.info("SemanticModule.getCombination: Se generaron " + listCase.size() + " nuevos casos");
			return listCase;
		}

		if (listClassName.size() > 0 && listMethodObject.size() > 0) {
			listCase = getCombination(listClassName, Constants.Dimension.Class.NAME, listMethodObject, Constants.Dimension.Method.OBJECT);
			logger.info("SemanticModule.getCombination: Se generaron " + listCase.size() + " nuevos casos");
			return listCase;
		}

		if (listClassName.size() > 0 && listMethodAction.size() > 0) {
			listCase = getCombination(listClassName, Constants.Dimension.Class.NAME, listMethodAction, Constants.Dimension.Method.ACTION);
			logger.info("SemanticModule.getCombination: Se generaron " + listCase.size() + " nuevos casos");
			return listCase;
		}

		if (listMethodAction.size() > 0 && listMethodObject.size() > 0) {
			listCase = getCombination(listMethodAction, Constants.Dimension.Method.ACTION, listMethodObject, Constants.Dimension.Method.OBJECT);
			logger.info("SemanticModule.getCombination: Se generaron " + listCase.size() + " nuevos casos");
			return listCase;
		}

		if (listClassName.size() > 0) {
			listCase = getCombination(listClassName, Constants.Dimension.Class.NAME);
			logger.info("SemanticModule.getCombination: Se generaron " + listCase.size() + " nuevos casos");
			return listCase;
		}

		if (listMethodObject.size() > 0) {
			listCase = getCombination(listMethodObject, Constants.Dimension.Method.OBJECT);
			logger.info("SemanticModule.getCombination: Se generaron " + listCase.size() + " nuevos casos");
			return listCase;
		}

		if (listMethodAction.size() > 0) {
			listCase = getCombination(listMethodAction, Constants.Dimension.Method.ACTION);
			logger.info("SemanticModule.getCombination: Se generaron " + listCase.size() + " nuevos casos");
			return listCase;
		}

		return listCase;
	}

	private List<Case> getCombination(List<String> list1, String dim1, List<String> list2, String dim2, List<String> list3, String dim3) {
		List<Case> listCase = new ArrayList<Case>();

		for (String string1 : list1) {
			Map<String, Dimension> mapDim1 = new HashMap<String, Dimension>();
			mapDim1.put(dim1, new Dimension(string1));

			for (String string2 : list2) {
				Map<String, Dimension> mapDim2 = new HashMap<String, Dimension>();
				mapDim2.put(dim2, new Dimension(string2));

				for (String string3 : list3) {
					Map<String, Dimension> mapDim3 = new HashMap<String, Dimension>();
					mapDim3.put(dim3, new Dimension(string3));

					Case semanticCase = new Case();
					semanticCase.setCase(targetCase);
					semanticCase.putDimension(mapDim1);
					semanticCase.putDimension(mapDim2);
					semanticCase.putDimension(mapDim3);

					listCase.add(semanticCase);
				}
			}
		}

		return listCase;
	}

	private List<Case> getCombination(List<String> list1, String dim1, List<String> list2, String dim2) {
		List<Case> listCase = new ArrayList<Case>();

		for (String string1 : list1) {
			Map<String, Dimension> mapDim1 = new HashMap<String, Dimension>();
			mapDim1.put(dim1, new Dimension(string1));

			for (String string2 : list2) {
				Map<String, Dimension> mapDim2 = new HashMap<String, Dimension>();
				mapDim2.put(dim2, new Dimension(string2));

				Case semanticCase = new Case();
				semanticCase.setCase(targetCase);
				semanticCase.putDimension(mapDim1);
				semanticCase.putDimension(mapDim2);

				listCase.add(semanticCase);
			}
		}

		return listCase;
	}

	private List<Case> getCombination(List<String> list1, String dim1) {
		List<Case> listCase = new ArrayList<Case>();

		for (String string1 : list1) {
			Map<String, Dimension> mapDim1 = new HashMap<String, Dimension>();
			mapDim1.put(dim1, new Dimension(string1));

			Case semanticCase = new Case();
			semanticCase.setCase(targetCase);
			semanticCase.putDimension(mapDim1);
			listCase.add(semanticCase);
		}

		return listCase;
	}
}
